home *** CD-ROM | disk | FTP | other *** search
- /*
- ModifyDialogs - Append items onto an existing Printing Manager dialog
-
- Version When Who What
- ------- ---- --- ----
- 0.1 9/11/86 Lew Original AppendDITL code.
- Rollins
-
- 1.0 3/01/88 Ginger Converted Lew's code to Pascal, and published
- Jernigan Technical Note #95.
-
- 2.0 5/01/91 Zz Fixed bug in AppendDITL - the call to PtrAndHand
- was being passed a size that was 2 bytes too large.
- Added Append2hdlg routine to support Help Manager
- balloons for the items appended to the dialog.
-
- -----
-
- This program is basically an updated version of the code in Technical Note #95,
- "How To Add Items to the Print Dialogs". There was a bug in the AppendDITL
- routine provided in that technote that has been fixed in this code.
-
- The latest addition is a routine called Append2hdlg. This routine is used
- to add Help Manager 'Balloons' for the items appended onto the dialog. As
- you might have guessed, the way you add items to the hdlg resource is very
- similar to the method used for DITL resources. You basically append the
- data, and then update the item count.
-
- This code was written under some time contraints, so it hasn't been completely
- tested, but it has been tested at least once with each of the Apple printer
- drivers currently available.
-
- It should also be noted that this code displays both the Page Setup and Print
- dialogs (unlike the original which only displayed the Print dialog), so there
- are extra routines. Basically, for every xxJobxxx routine, there is now a
- xxStlxxx routine. The routines are basically identical, the only difference
- is the substitution of Stl for Job in the appropriate places. The duplication
- of code is actually meant to make things a little clearer.
-
- I hope this helps,
-
- ...Zz
-
-
- -----------------------------------------------------------------------------
- NOTE: Apple reserves the top half of the screen (where the current DITL
- items are located). Applications may use the bottom half of the screen to add
- items, but should not change any items in the top half of the screen. An
- application should expand the print dialogs only as much as is absolutely
- necessary.
- -----------------------------------------------------------------------------
- */
-
- #define MPW 1
- #define nil 0L
-
- #define MyDITL 256 /* resource ID of my DITL to be spliced on to job/stl dialog */
- #define Myhdlg MyDITL /* resource ID of my hdlg to be spliced on to job/stl dialog */
- #define JobDlgID -8191 /* resource ID of 'Job' or 'Print' DLOG, DITL, & hdlg */
- #define StlDlgID -8192 /* resource ID of 'Style' or 'PageSetup' DLOG, DITL, & hdlg */
- #define MyDFirstBox 1 /* Item number of first box in my DITL */
- #define MyDSecondBox 2
- #define MyDThirdBox 3
-
- #include <Values.h>
- #include <Types.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Desk.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <SegLoad.h>
- #include <Files.h>
- #include <OSUtils.h>
- #include <OSEvents.h>
- #include <DiskInit.h>
- #include <Packages.h>
- #include <Traps.h>
- #include <Printing.h>
-
-
- /* Types for accessing the Printing Manager dialog resources. */
- static TPPrDlg PrtJobDialog; /* pointer to job dialog */
- static TPPrDlg PrtStlDialog; /* pointer to job dialog */
-
- struct DITLItem { /* First, a single item */
- Handle itmHndl; /* Handle or procedure pointer for this item */
- Rect itmRect; /* Display rectangle for this item */
- SignedByte itmType; /* Item type for this item — 1 byte */
- SignedByte itmData[]; /* Length byte of data */
- }; /*DITLItem*/
-
- typedef struct DITLItem DITLItem, *pDITLItem, **hDITLItem;
-
- struct ItemList { /* Then, the list of items */
- short dlgMaxIndex; /* Number of items minus 1 */
- struct DITLItem DITLItems[]; /* Array of items */
- }; /*ItemList*/
-
- typedef struct ItemList ItemList, *pItemList, **hItemList;
- typedef short *IntPtr;
-
- /* Types for accessing the Help Manager 'hdlg' resources. */
- typedef struct {
- short hdlgVers;
- short hdlg1stItem;
- long hdlgOptions;
- short hdlgProcID;
- short hdlgVarCode;
- short hdlgNumItems;
- } hdlgHeader, *hdlgHeaderPtr, **hdlgHeaderHdl;
-
- typedef short *IntPtr, **IntHdl;
-
-
- /* Declare ‘pascal’ functions and procedures */
- #ifndef MPW
- pascal Boolean PrDlgMain(); /* Print manager’s dialog handler */
- pascal TPPrDlg PrJobInit(); /* Gets standard print job dialog. */
- pascal TPPrDlg MyJobDlgInit(); /* Our extention to PrJobInit */
- pascal void MyJobItems(); /* Our modal item handler */
- pascal TPPrDlg PrStlInit(); /* Gets standard print job dialog. */
- pascal TPPrDlg MyStlDlgInit(); /* Our extention to PrJobInit */
- pascal void MyStlItems(); /* Our modal item handler */
- #endif
-
-
- THPrint hPrintRec; /* handle to print record */
- short FirstBoxValue = 0; /* value of our first additional box */
- short SecondBoxValue = 0; /* value of our second addtl. box */
- short ThirdBoxValue = 0; /* value of our third addtl. box */
- long prFirstItem; /* save our first item here */
- ProcPtr prPItemProc; /* we need to store the old itemProc here */
-
- WindowPtr MyWindow;
- OSErr err;
- Str255 myStr;
-
-
- /*------------------------------------------------------------------------*/
-
- short AppendDITL(theDialog, theDITLID)
- DialogPtr theDialog;
- short theDITLID;
-
- /* version 0.1 9/11/86 Lew Rollins of Human-Systems Interface Group*/
- /* this routine still needs some error checking */
-
- /* This routine appends all of the items of a specified DITL
- onto the end of a specified DLOG — We don’t even need to know the format
- of the DLOG */
-
- /* this will be done in 3 steps:
- 1. append the items of the specified DITL onto the existing DLOG
- 2. expand the original dialog window as required
- 3. return the adjusted number of the first new user item
- */
-
- {
- Point offset; /* Used to offset rectangles of items being appended */
- Rect maxRect; /* Used to track increases in window size */
- hItemList hDITL; /* Handle to DITL being appended */
- pDITLItem pItem; /* Pointer to current item being appended */
- hItemList hItems; /* Handle to DLOG’s item list */
- short firstItem; /* Number of where first item is to be appended */
- short newItems, /* Count of new items */
- dataSize, /* Size of data for current item */
- i; /* Working index */
- union {
- short Int;
- SignedByte SBArray[2];
- } USB;
-
-
- /*
- Using the original DLOG
-
- 1. Remember the original window Size.
- 2. Set the offset Point to be the bottom of the original window.
- 3. Subtract 5 pixels from bottom and right, to be added
- back later after we have possibly expanded window.
- 4. Get working Handle to original item list.
- 5. Calculate our first item number to be returned to caller.
- 6. Get locked Handle to DITL to be appended.
- 7. Calculate count of new items.
- */
-
- maxRect = ((DialogPeek)theDialog)->window.port.portRect;
- offset.v = maxRect.bottom;
- offset.h = 0;
- maxRect.bottom = maxRect.bottom - 5;
- maxRect.right = maxRect.right - 5;
-
- hItems = (hItemList)(((DialogPeek)theDialog)->items);
- firstItem = (*hItems)->dlgMaxIndex + 2;
-
- hDITL = (hItemList)GetResource('DITL', theDITLID);
- HLock((Handle)hDITL);
- newItems = (*hDITL)->dlgMaxIndex + 1;
-
- /*
- For each item,
- 1. Offset the rectangle to follow the original window.
- 2. Make the original window larger if necessary.
- 3. fill in item Handle according to type.
- */
- pItem = (*hDITL)->DITLItems;
- for (i = 1; i <= newItems; i++) {
- OffsetRect(&pItem->itmRect, offset.h, offset.v);
- UnionRect(&pItem->itmRect, &maxRect, &maxRect);
-
- USB.Int = 0; /*zero things out*/
- USB.SBArray[1] = pItem->itmData[0];
-
- /* Strip enable bit since it doesn’t matter here. */
- switch (pItem->itmType & 0x7f) {
- case userItem: /* Can’t do anything meaningful with user items. */
- pItem->itmHndl = nil;
- break;
-
- case (ctrlItem + btnCtrl):
- case (ctrlItem + chkCtrl):
- case (ctrlItem + radCtrl): /*build Control */
- pItem->itmHndl = (Handle)
- NewControl(theDialog, /* theWindow */
- &pItem->itmRect, /* boundsRect */
- ((StringPtr)(&pItem->itmData[0])), /* title */
- true, /* visible */
- 0,0,1, /* value, min, max */
- (pItem->itmType & 0x03), /* procID */
- 0); /* refCon */
- break;
-
- case ctrlItem + resCtrl: /* Get resource based Control */
- pItem->itmHndl = (Handle)
- GetNewControl((*(IntPtr)&pItem->itmData[1]), /* controlID */
- theDialog); /* theWindow */
- (*(ControlHandle)pItem->itmHndl)->contrlRect = pItem->itmRect; /*give it the right
- rectangle*/
- /* An actionProc for a Control should be installed here */
- break;
-
- case (statText):
- case (editText): /* Both need Handle to a copy of their text. */
- err = PtrToHand(&pItem->itmData[1], /* Start of data */
- &pItem->itmHndl, /* Address of new Handle */
- USB.Int); /* Length of text */
- break;
-
- case iconItem: /* Icon needs resource Handle. */
- pItem->itmHndl = GetIcon(*(IntPtr)&pItem->itmData[1]); /* ICON resID */
- break;
-
- case picItem: /* Picture needs resource Handle. */
- pItem->itmHndl = (Handle)GetPicture(*(IntPtr)&pItem->itmData[1]); /*PICT resID*/
- break;
-
- default:
- pItem->itmHndl = nil;
- break;
-
- } /*switch*/
-
- dataSize = ((USB.Int + 1) & 0xfffe);
-
- /*now advance to next item*/
- pItem = (pDITLItem)((Ptr)(pItem) + dataSize + sizeof(DITLItem));
- } /*for*/
-
- err = PtrAndHand
- ((Ptr)(*hDITL)->DITLItems, (Handle)hItems, GetHandleSize((Handle)hDITL) - 2);
-
- (*hItems)->dlgMaxIndex = (*hItems)->dlgMaxIndex + newItems;
- HUnlock((Handle)hDITL);
- ReleaseResource((Handle)hDITL);
- maxRect.bottom = maxRect.bottom + 5;
- maxRect.right = maxRect.right + 5;
- SizeWindow(theDialog, maxRect.right, maxRect.bottom, true);
- return firstItem;
- } /*AppendDITL*/
-
- /*------------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------------*/
- /* */
- /* Append2hdlg - Append one 'hdlg' resource onto another. */
- /* */
- /* So what we want to do here is append the hdlg resource with resource ID */
- /* srcID, onto the end of the hdlg resource, ID dstID. Here's what these */
- /* things look like: */
- /* */
- /* *-----------------------------------* */
- /* | Header (version, options, etc.) | */
- /* *-----------------------------------* */
- /* / # of items in item array / */
- /* *-----------------------------------* */
- /* | Missing item marker | */
- /* *-----------------------------------* */
- /* / Array of items / */
- /* / … / */
- /* *-----------------------------------* */
- /* */
- /* Okay, so this chart breaks up the resource into logical blocks for this */
- /* excercise. We're most interested in the blocks marked with '/'s. The */
- /* first one of these is the # of items in the item array. We need to read */
- /* this field in the source hdlg to know how many items we are adding. We */
- /* need to update this field in the destination hdlg so the Help Manager */
- /* knows that we added some items. This missing item is a generic item */
- /* used by the Help Manager anytime it can't find a resource entry for an */
- /* item. In most hdlg resources, this item is simply HMSkipItem (a no op), */
- /* but this code makes no assumptions about that. It does however assume */
- /* that you want to preserve the missing item in the DESTINATION hdlg, */
- /* rather than copying from the source. */
- /* So this code does this: */
- /* */
- /* Source Destination */
- /* *---------------------------* *---------------------------* */
- /* | Header | | Header | */
- /* | (version, options, etc.)| | (version, options, etc.)| */
- /* *---------------------------* *---------------------------* */
- /* / # of items in item array /--Add->/ # of items in item array / */
- /* *---------------------------* *---------------------------* */
- /* | Missing item | | Missing item | */
- /* *---------------------------* *---------------------------* */
- /* / Array of items / */
- /* / … / */
- /* *---------------------------*-Copy->*---------------------------* */
- /* / Array of items / */
- /* / … / */
- /* *---------------------------* */
- /* */
- /* Nothing to it. The number of items is updated by adding the count from */
- /* source hdlg, no 'minus 1' or anything tricky. Then just append the item */
- /* array from the source onto the end of the destination. The Help Manager */
- /* finds the new items no problem. Okay, but since we are a guest in some- */
- /* one elses closet, we need to play some games with memory. First of all, */
- /* we make sure that the destination 'hdlg' resource isn't already in mem- */
- /* ory using the ol' SetResLoad trick. If it's not there, we load it, but */
- /* in any case, the hdlg is loaded into memory. Once there, we make the */
- /* rather large assumption that it's not going anywhere. This means that */
- /* we don't lock the hdlg handle, we don't even mark it non-purgeable. The */
- /* assumption is that the Help Manager will be finding the resource as soon */
- /* as we are done with it, and he will take care of keeping it around after */
- /* that. Once the dialog is dismissed, the resource is naturally purged, */
- /* along with the changes that we made to it. Since we never told the */
- /* Resource Manager that we had changed the resource, it doesn't try to save*/
- /* it. */
- void Append2hdlg(srcResID, dstResID)
- short srcResID, dstResID;
- {
- Handle srcHdl, dstHdl;
- Ptr srcPtr, dstPtr;
- short srcLength, dstLength;
- short missingItmSz;
- SignedByte dstHState;
-
-
- srcHdl = GetResource('hdlg', srcResID);
- if (srcHdl != nil) {
- SetResLoad(false); /* System Resource, make sure it’s not */
- dstHdl = GetResource('hdlg', dstResID); /* already loaded. */
- SetResLoad(true);
- if (*dstHdl == 0)
- dstHdl = GetResource('hdlg', dstResID);
- dstHState = HGetState(dstHdl);
-
- if (dstHdl != nil) {
- srcPtr = (Ptr)*srcHdl + sizeof(hdlgHeader);
- missingItmSz = *((IntPtr)srcPtr);
- srcLength = GetHandleSize(srcHdl) - (sizeof(hdlgHeader) - missingItmSz);
-
- dstLength = GetHandleSize(dstHdl);
- SetHandleSize(dstHdl, dstLength + srcLength);
- if (MemError() != noErr) {
- DebugStr("\pMemError"); /* Use this error handler, go to jail. */
- ExitToShell(); /* It's the law! */
- }
- dstPtr = (Ptr)*dstHdl + dstLength;
- srcPtr = (Ptr)*srcHdl + sizeof(hdlgHeader) + missingItmSz;
-
- HLock(srcHdl);
- HLock(dstHdl);
-
- BlockMove(srcPtr, dstPtr, srcLength);
-
- HUnlock(srcHdl);
- HSetState(dstHdl, dstHState);
-
- ((hdlgHeaderPtr)*dstHdl)->hdlgNumItems += ((hdlgHeaderPtr)*srcHdl)->hdlgNumItems;
-
- }
- }
- ReleaseResource(srcHdl);
- }
-
- /*-----------------------------------------------------------------------*/
-
- /* here's the analogue to the SF dialog hook */
-
- typedef pascal Boolean (*PrDialogProcPtr)(TPPrDlg theDialog, short itemNo);
-
- pascal void MyJobItems(theDialog,itemNo)
- TPPrDlg theDialog;
- short itemNo;
-
- { /* MyJobItems */
- short myItem;
- short firstItem;
-
- short itemType; /* needed for GetDItem/SetDItem call */
- Handle itemH;
- Rect itemBox;
-
- firstItem = prFirstItem; /* remember, we saved this in myJobDlgInit */
- myItem = itemNo - firstItem + 1; /* "localize" current item No */
- if (myItem > 0) /* if localized item > 0, it's one of ours */
- {
- /* find out which of our items was hit */
- GetDItem((DialogPtr)theDialog, itemNo, &itemType, &itemH, &itemBox);
- switch (myItem)
- {
- case MyDFirstBox:
- /* invert value of FirstBoxValue and redraw it */
- FirstBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, FirstBoxValue);
- break;
-
- case MyDSecondBox:
- /* invert value of SecondBoxValue and redraw it */
- SecondBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, SecondBoxValue);
- break;
- case MyDThirdBox:
- /* invert value of SecondBoxValue and redraw it */
- ThirdBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, ThirdBoxValue);
- break;
- default:
- Debugger(); /* OH OH */
- } /* switch */
- } /* if (myItem > 0) */
- else /* chain to standard item handler, whose address is saved in prPItemProc */
- {
- (*((PrDialogProcPtr)prPItemProc))(theDialog,itemNo);
- }
- } /* MyJobItems */
-
- /*----------------------------------------------------------------------------*/
-
- pascal TPPrDlg MyJobDlgInit(hPrint)
- THPrint hPrint;
- #pragma unused (hPrint);
-
- /* this routine appends items to the standard job dialog and sets up the
- user fields of the printing dialog record TPRDlg
- This routine will be called by PrDlgMain */
- {
- short firstItem; /* first new item number */
- short itemType; /* needed for GetDItem/SetDItem call */
- Handle itemH;
- Rect itemBox;
-
- /* First append onto the DITL. */
- firstItem = AppendDITL(PrtJobDialog, MyDITL); /*call routine to do this */
-
- prFirstItem = firstItem; /* save this so MyJobItems can find it */
-
- /* now we'll set up our DITL items -- The "First Box" */
- GetDItem((DialogPtr)PrtJobDialog, firstItem, &itemType, &itemH, &itemBox);
- SetCtlValue((ControlHandle)itemH, FirstBoxValue);
-
- /* now we'll set up the second of our DITL items -- The "Second Box" */
- GetDItem((DialogPtr)PrtJobDialog, firstItem+1, &itemType, &itemH, &itemBox);
- SetCtlValue((ControlHandle)itemH,SecondBoxValue);
-
- /* Now comes the part where we patch in our item handler. We have to save
- the old item handler address, so we can call it if one of the standard items is hit, and put our item handler's address
- in pItemProc field of the TPrDlg struct
- */
-
- prPItemProc = (ProcPtr)PrtJobDialog->pItemProc;
-
- /* Now we'll tell the modal item handler where our routine is */
- PrtJobDialog->pItemProc = (PItemProcPtr)MyJobItems;
-
- /* PrDlgMain expects a pointer to the modified dialog to be returned.... */
- return PrtJobDialog;
-
- } /*myJobDlgInit*/
-
-
- /*------------------------------------------------------------------------*/
-
- pascal void MyStlItems(theDialog,itemNo)
- TPPrDlg theDialog;
- short itemNo;
-
- { /* MyJobItems */
- short myItem;
- short firstItem;
-
- short itemType; /* needed for GetDItem/SetDItem call */
- Handle itemH;
- Rect itemBox;
-
- firstItem = prFirstItem; /* remember, we saved this in myJobDlgInit */
- myItem = itemNo - firstItem + 1; /* "localize" current item No */
- if (myItem > 0) /* if localized item > 0, it's one of ours */
- {
- /* find out which of our items was hit */
- GetDItem((DialogPtr)theDialog, itemNo, &itemType, &itemH, &itemBox);
- switch (myItem)
- {
- case MyDFirstBox:
- /* invert value of FirstBoxValue and redraw it */
- FirstBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, FirstBoxValue);
- break;
-
- case MyDSecondBox:
- /* invert value of SecondBoxValue and redraw it */
- SecondBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, SecondBoxValue);
- break;
- case MyDThirdBox:
- /* invert value of SecondBoxValue and redraw it */
- ThirdBoxValue ^= 1;
- SetCtlValue((ControlHandle)itemH, ThirdBoxValue);
- break;
- default:
- Debugger(); /* OH OH */
- } /* switch */
- } /* if (myItem > 0) */
- else /* chain to standard item handler, whose address is saved in prPItemProc */
- {
- (*((PrDialogProcPtr)prPItemProc))(theDialog,itemNo);
- }
- } /* MyStlItems */
-
- /*----------------------------------------------------------------------------*/
-
- pascal TPPrDlg MyStlDlgInit(hPrint)
- THPrint hPrint;
- #pragma unused (hPrint);
-
- /* this routine appends items to the standard job dialog and sets up the
- user fields of the printing dialog record TPRDlg
- This routine will be called by PrDlgMain */
- {
- short firstItem; /* first new item number */
- short itemType; /* needed for GetDItem/SetDItem call */
- Handle itemH;
- Rect itemBox;
-
- /* First append onto the DITL. */
- firstItem = AppendDITL(PrtStlDialog, MyDITL); /*call routine to do this */
-
- prFirstItem = firstItem; /* save this so MyStlItems can find it */
-
- /* now we'll set up our DITL items -- The "First Box" */
- GetDItem((DialogPtr)PrtStlDialog, firstItem, &itemType, &itemH, &itemBox);
- SetCtlValue((ControlHandle)itemH, FirstBoxValue);
-
- /* now we'll set up the second of our DITL items -- The "Second Box" */
- GetDItem((DialogPtr)PrtStlDialog, firstItem+1, &itemType, &itemH, &itemBox);
- SetCtlValue((ControlHandle)itemH,SecondBoxValue);
-
- /* Now comes the part where we patch in our item handler. We have to save
- the old item handler address, so we can call it if one of the standard items is hit, and put our item handler's address
- in pItemProc field of the TPrDlg struct
- */
-
- prPItemProc = (ProcPtr)PrtStlDialog->pItemProc;
-
- /* Now we'll tell the modal item handler where our routine is */
- PrtStlDialog->pItemProc = (PItemProcPtr)MyStlItems;
-
- /* PrDlgMain expects a pointer to the modified dialog to be returned.... */
- return PrtStlDialog;
-
- } /*myStlDlgInit*/
-
-
- /*------------------------------------------------------------------------*/
-
- OSErr Print()
- {
- TPPrPort pPrintPort;
-
- /* call PrJobInit to get pointer to the invisible job dialog */
- hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));
- if (hPrintRec) {
- PrintDefault(hPrintRec);
-
- PrValidate(hPrintRec);
- if (PrError() != noErr)
- return PrError();
-
- /*-------------------------------------*/
-
-
- PrtStlDialog = PrStlInit(hPrintRec);
- if (PrError() != noErr)
- return PrError();
-
- Append2hdlg(Myhdlg, StlDlgID);
-
- if (!PrDlgMain(hPrintRec, MyStlDlgInit))
- return cancel;
-
-
- /*-------------------------------------*/
-
- PrtJobDialog = PrJobInit(hPrintRec);
- if (PrError() != noErr)
- return PrError();
-
- /* Next append to the hdlg resource */
- Append2hdlg(Myhdlg, JobDlgID);
-
- if (!PrDlgMain(hPrintRec, MyJobDlgInit)) /* this line does all the stuff */
- return cancel;
-
- /*-------------------------------------*/
-
- pPrintPort = PrOpenDoc(hPrintRec, nil, nil);
- if (PrError() == noErr) {
- PrOpenPage(pPrintPort, nil);
- if (PrError() == noErr) {
-
- SetPort(&pPrintPort->gPort);
- MoveTo(100, 100);
- DrawString("\pTesting...");
-
- PrClosePage(pPrintPort);
- } else
- return PrError();
- PrCloseDoc(pPrintPort);
- } else
- return PrError();
- }
- } /* Print */
-
-
- /*-----------------------------------------------------------------------*/
- main()
- {
- #ifdef MPW
- InitGraf(&qd.thePort);
- #else
- InitGraf(&thePort);
- #endif
- InitFonts();
- InitWindows();
- InitMenus();
- InitDialogs(nil);
- InitCursor();
-
- /* call the routine that does printing */
- PrOpen();
- err = Print();
-
- PrClose();
- } /* main */
-
-